package com.atguigu.gmall.activity.receiver;

import com.atguigu.gmall.activity.mapper.SeckillGoodsMapper;
import com.atguigu.gmall.activity.service.SeckillGoodsService;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.activity.UserRecode;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.SaslConfig;
import lombok.SneakyThrows;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;

/**
 * @Author atguigu-mqx
 * @Description TODO
 * @Date 2023/5/30 14:49
 * @Version 1.0
 */
@Component
public class SeckillReceiver {

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;

    @Autowired
    private SeckillGoodsService seckillGoodsService;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 商品预热
     * @param msg
     * @param message
     * @param channel
     */
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_TASK_1,durable = "true",autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
            key = {MqConst.ROUTING_TASK_1}
    ))
    public void importDataToRedis(String msg, Message message, Channel channel){
        try {
            //  商品预热代码.
            //  select * from seckill_goods where date_format(start_time,'%Y-%m-%d') = '2023-05-30' and status ='1' and stock_count>0;
            LambdaQueryWrapper<SeckillGoods> seckillGoodsLambdaQueryWrapper = new LambdaQueryWrapper<>();
            seckillGoodsLambdaQueryWrapper.eq(SeckillGoods::getStatus,"1").gt(SeckillGoods::getStockCount,0);
//          seckillGoodsLambdaQueryWrapper.apply("date_format(start_time,'%Y-%m-%d')", DateUtil.formatDate(new Date()));
            seckillGoodsLambdaQueryWrapper.apply("DATE_FORMAT(start_time,'%Y-%m-%d') = " + "'" + DateUtil.formatDate(new Date()) + "'");
            List<SeckillGoods> seckillGoodsList = seckillGoodsMapper.selectList(seckillGoodsLambdaQueryWrapper);
            //  判断
            if (!CollectionUtils.isEmpty(seckillGoodsList)){
                //  循环遍历.
                for (SeckillGoods seckillGoods : seckillGoodsList) {
                    //  放入缓存. 存储一个hash
                    //  声明一个key
                    String seckillKey = RedisConst.SECKILL_GOODS;

                    //  如果缓存中已经有这个数据了，不能发生覆盖
                    Boolean result = this.redisTemplate.opsForHash().hasKey(seckillKey, seckillGoods.getSkuId().toString());
                    if (result){
                        //  不能覆盖
                        continue;
                    }
                    //  商品的数量放入redis; 使用队列存储 10
                    Integer stockCount = seckillGoods.getStockCount();
                    for (Integer i = 0; i < stockCount; i++) {
                        //  list -- lpush key value; key = seckill:stock:skuId skuId;
                        this.redisTemplate.opsForList().leftPush(RedisConst.SECKILL_STOCK_PREFIX+seckillGoods.getSkuId(),seckillGoods.getSkuId().toString());
                    }
                    //  存储到缓存中。
                    this.redisTemplate.opsForHash().put(seckillKey,seckillGoods.getSkuId().toString(),seckillGoods);
                    //  设置商品的状态位: 25:1
                    this.redisTemplate.convertAndSend("seckillpush",seckillGoods.getSkuId()+":1");
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        //  手动确认：
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }

    //  监听秒杀队列信息数据
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_SECKILL_USER,durable = "true",autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_SECKILL_USER),
            key = {MqConst.ROUTING_SECKILL_USER}
    ))
    public void seckillUser(UserRecode userRecode,Message message,Channel channel){
        try {
            //  判断
            if (null != userRecode){
                //  调用服务层方法。
                seckillGoodsService.seckillUser(userRecode);
            }
        } catch (Exception e) {
            //  打印日志...
            throw new RuntimeException(e);
        }

        //  手动确认
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }

    /**
     * 减库存
     * @param skuId
     * @param message
     * @param channel
     */
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_SECKILL_STOCK,durable = "true",autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_SECKILL_STOCK),
            key = {MqConst.ROUTING_SECKILL_STOCK}
    ))
    public void updateStock(Long skuId, Message message ,Channel channel){
        try {
            //  判断
            if (null != skuId){
                //  调用服务层方法.
                seckillGoodsService.updateStock(skuId);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        //  手动确认
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }

    /**
     * 秒杀结束删除数据
     * @param message
     * @param channel
     */
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_TASK_18,durable = "true",autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
            key = {MqConst.ROUTING_TASK_18}
    ))
    public void clearData(Message message , Channel channel){
        try {
            //  查询当天秒杀结束商品：
            LambdaQueryWrapper<SeckillGoods> seckillGoodsLambdaQueryWrapper = new LambdaQueryWrapper<>();
            seckillGoodsLambdaQueryWrapper.eq(SeckillGoods::getStatus,"1");
            seckillGoodsLambdaQueryWrapper.le(SeckillGoods::getEndTime,new Date());
            List<SeckillGoods> seckillGoodsList = seckillGoodsMapper.selectList(seckillGoodsLambdaQueryWrapper);

            //  循环遍历
            if (!CollectionUtils.isEmpty(seckillGoodsList)){
                for (SeckillGoods seckillGoods : seckillGoodsList) {
                    //  商品的剩余库存.
                    this.redisTemplate.delete(RedisConst.SECKILL_STOCK_PREFIX+seckillGoods.getSkuId());
                }
            }

            //  删除商品数据库：
            this.redisTemplate.delete(RedisConst.SECKILL_GOODS);
            //  删除预下单数据：如果用户没有点击提交订单，缓存中是有预下单记录的
            this.redisTemplate.delete(RedisConst.SECKILL_ORDERS);
            //  删除真正下单数据：
            this.redisTemplate.delete(RedisConst.SECKILL_ORDERS_USERS);

            //  更新mysql 数据库，将这个商品的状态更新为不可以秒杀。
            SeckillGoods seckillGoods = new SeckillGoods();
            //  0 表示秒杀结束
            seckillGoods.setStatus("0");
            //  update seckill_goods set status='0' where statu='1' and end_time<now();
            seckillGoodsMapper.update(seckillGoods,seckillGoodsLambdaQueryWrapper);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        //  手动确认：
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }
}
